package com.heima.admin.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.admin.mapper.AdChannelMapper;
import com.heima.admin.mapper.AdSensitiveMapper;
import com.heima.admin.service.WemediaNewsAutoScanService;
import com.heima.aliyun.config.GreenImageScan;
import com.heima.aliyun.config.GreenTextScan;
import com.heima.common.exception.CustException;
import com.heima.feigns.article.ArticleFeign;
import com.heima.feigns.wemedia.WemediaFeign;
import com.heima.model.admin.pojos.AdChannel;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.common.SensitiveWordUtil;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Jt
 * @date 2021/4/18 16:11
 */
@Service
@Slf4j
public class WemediaNewsAutoScanServiceImpl implements WemediaNewsAutoScanService {

    @Resource
    private WemediaFeign wemediaFeign;

    @Resource
    private AdSensitiveMapper adSensitiveMapper;

    @Resource
    private GreenTextScan greenTextScan;

    @Resource
    private GreenImageScan greenImageScan;

    @Resource
    private AdChannelMapper adChannelMapper;

    @Resource
    private ArticleFeign articleFeign;

    @Value("${file.oss.web-site}")
    String webSite;


    /**
     * 自媒体文章的自动审核
     *
     * @param wmNewsId
     */
    @Override
    @GlobalTransactional
    public void autoScanByMediaNewsId(Integer wmNewsId) {
//        1. 检查id是否正确
        if (ObjectUtils.isEmpty(wmNewsId)) {
            log.error("自动审核失败,文章id===>{}", wmNewsId);
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID, "对应自媒体文章id不存在");
            return;
        }
//        2. 根据文章的id查询自媒体的文章信息
        WmNews wmNews = wemediaFeign.findById(wmNewsId);
        if (ObjectUtils.isEmpty(wmNews)) {
            log.error("自动审核失败,文章信息为空===>{}", wmNewsId);
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID, "对应的自媒体文章信息为空");
            return;
        }
//        3. 检查文章状态是否为4 , 并且发布时间是否小于等于当前时间
        if (wmNews.getStatus().equals(WmNews.Status.ADMIN_SUCCESS.getCode())
                && wmNews.getPublishTime().before(new Date())) {
//        4. 如果为true , 调用发布文章方法,return
            publishArticle(wmNews);
            return;
        }
//        5. 检查文章状态是否为8 , 并且发布时间是否小于等于现在的时间
        if (wmNews.getStatus().equals(WmNews.Status.SUCCESS.getCode())
                && wmNews.getPublishTime().before(new Date())) {
//        6. 如果为true,调用发布文章的方法,return
            publishArticle(wmNews);
            return;
        }
//        7. 检查文章状态是否为1 , 待审核状态,需要审核
        if (wmNews.getStatus().equals(WmNews.Status.SUBMIT.getCode())) {
            // : 2021/4/18 抽取文章内容中的所有文本(String) 和所有图片(List<url>)
            Map<String, Object> contentAndImagesResult = handleTextAndImages(wmNews);
            // : 2021/4/18 基于敏感词,使用DFA算法进行敏感词审核 不通过:文章状态改为2
            boolean sensitiveScan = handleSensitive((String) contentAndImagesResult.get("content"), wmNews);
            if (!sensitiveScan)
                return;
            // : 2021/4/18 基于阿里云的内容安全 进行文本内容审核 不通过文章状态改为2,不确定文章状态改为3
            boolean textScan = handleTextScan((String) contentAndImagesResult.get("content"), wmNews);
            if (!textScan)
                return;
            // : 2021/4/18 基于阿里云的内容安全 进行图片内容审核 不通过文章状态改为2,不确定文章状态改3
            boolean imageScan = handleImageScan((List<String>) contentAndImagesResult.get("images"), wmNews);
            if (!imageScan)
                return;
            // : 2021/4/18 审核通过 判断文章发布时间是否大于当前时间 文章状态改为8
            if (wmNews.getPublishTime().after(new Date())) {
                updateWmNews(wmNews, (short) 8, "审核通过");
                return;
            }
            // : 2021/4/18 审核通过 发布文章方法
            publishArticle(wmNews);

        }
    }


    /**
     * 阿里云图片审核
     *
     * @param images 待审核图片
     * @param wmNews 文章
     * @return
     */
    private boolean handleImageScan(List<String> images, WmNews wmNews) {
        boolean flag = true;
        try {
            Map map = greenImageScan.imageUrlScan(images);
            String suggestion = (String) map.get("suggestion");
            if ("block".equals(suggestion)) {
                flag = false;
                updateWmNews(wmNews, (short) 2, "图片中有违规信息");
            } else if ("review".equals(suggestion)) {
                flag = false;
                updateWmNews(wmNews, (short) 3, "图片有不确定信息,转人工审核");
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("阿里云图片审核失败 文章id==>{} 原因===> {}", wmNews.getId(), e);
            flag = false;
            updateWmNews(wmNews, (short) 3, "阿里云图片审核失败,转为待人工审核");
        }
        return flag;
    }


    /**
     * 阿里云 文本审核
     *
     * @param content
     * @param wmNews
     * @return
     */
    private boolean handleTextScan(String content, WmNews wmNews) {
        boolean flag = true;
        try {
            Map map = greenTextScan.greenTextScan(content);
            String suggestion = (String) map.get("suggestion");
            if ("block".equals(suggestion)) {
                flag = false;
                updateWmNews(wmNews, (short) 2, "文本内容有违规信息");
            } else if ("review".equals(suggestion)) {
                flag = false;
                updateWmNews(wmNews, (short) 3, "文本有不确定信息,转人工审核");
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("阿里云文本失败 文章id===> {} 原因===>{}", wmNews.getId(), e);
            flag = false;
            updateWmNews(wmNews, (short) 3, "阿里云文本审核失败,转待人工审核");
        }
        return flag;
    }


    /**
     * 敏感词的审核
     *
     * @param content 待审核内容
     * @param wmNews  文章信息
     * @return
     */
    private boolean handleSensitive(String content, WmNews wmNews) {
        boolean flag = true;
//        1. 查询数据库中敏感词的列表
        List<String> allSensitive = adSensitiveMapper.findAllSensitive();
//        2. 使用DFA工具类 生成DFA数据模型
        SensitiveWordUtil.initMap(allSensitive);
//        3. 使用DFA工具类 检查是否包含敏感词
        Map<String, Integer> sensitiveResult = SensitiveWordUtil.matchWords(content);
        if (sensitiveResult != null && !sensitiveResult.isEmpty()) {
            flag = false;
            updateWmNews(wmNews, (short) 2, "文章中包含敏感词: " + sensitiveResult);
        }
//        4. 如果包含敏感词 则修改wmNews状态为2
        return flag;
    }

    /**
     * 修改自媒体文章信息
     *
     * @param wmNews
     * @param status
     * @param reason
     */
    private void updateWmNews(WmNews wmNews, Short status, String reason) {
        wmNews.setStatus(status);
        wmNews.setReason(reason);
        ResponseResult responseResult = wemediaFeign.updateWmNews(wmNews);
        if (responseResult.getCode() != 0) {
            log.error("修改自媒体文章状态失败 id: {}", wmNews.getId());
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID, responseResult.getErrorMessage());
        }
    }

    /**
     * 抽取文章中所有文章内容和图片内容
     *
     * @param wmNews
     * @return
     */
    private Map<String, Object> handleTextAndImages(WmNews wmNews) {
//        文章内容的json字符串转为List<Map> 集合
        String contentJson = wmNews.getContent();
        List<Map> contentMap = JSON.parseArray(contentJson, Map.class);
        if (contentJson.isEmpty() || contentMap.isEmpty()) {
            log.error("自动审核失败,待审核的文章内容为空===>{}", wmNews.getId());
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID, "自动审核失败,待审核的文章内容为空");
        }
//        1. 抽取文本(文章标题 文章内容)
        String content = contentMap.stream()
                .filter(map -> map.get("type").equals("text")) // 过滤数据
                .map(map -> (String) map.get("value"))
                .collect(Collectors.joining("_hmtt_"));
        content = wmNews.getTitle() + "_hmtt_" + content;
//        2. 抽取内容图片
        List<String> imageList = contentMap.stream()
                .filter(map -> map.get("type").equals("image")) // 过滤数据
                .map(map -> (String) map.get("value"))
                .distinct()
                .collect(Collectors.toList());
//        3. 解析封面图片
        String images = wmNews.getImages();
        if (StringUtils.isNotBlank(images)) {
            Arrays.stream(images.split(","))
                    .map(url -> webSite + url)
                    .distinct()
                    .forEach(imageList::add);
        }
//        4. 封装返回结果
        HashMap<String, Object> map = new HashMap<>();
        map.put("content", content);
        map.put("images", imageList);
        return map;
    }

    /**
     * 发布文章
     *
     * @param wmNews
     */
    private void publishArticle(WmNews wmNews) {
//        远程调用article微服务保存相关的文章信息
        ResponseResult responseResult = saveArticle(wmNews);
        if (responseResult.getCode() != 0) {
            log.error("远程调文章微服务保存文章方法出错==>{}", responseResult.getErrorMessage());
            CustException.cust(AppHttpCodeEnum.SERVER_ERROR, responseResult.getErrorMessage());
        }
//        保存文章方法 要返回articleId 把id设置到wm_news
        wmNews.setArticleId((Long) responseResult.getData());
        updateWmNews(wmNews, (short) 9, "文章审核通过");
    }

    /**
     * 远程调用article微服务 保存文章 也即是保存三张表
     *
     * @param wmNews
     * @return
     */
    private ResponseResult saveArticle(WmNews wmNews) {
//        封装调用的dto参数
        ArticleDto articleDto = new ArticleDto();
//        拷贝wmNews相关属性到articleDto
        BeanUtils.copyProperties(wmNews, articleDto);
//        文章可能已经发布过,但下架之后还可以对文章进行修改 修改之后重新审核
        articleDto.setId(null);
        if (wmNews.getArticleId() != null) {

            articleDto.setId(wmNews.getArticleId());
        }
        articleDto.setLayout(wmNews.getType());//0 无图 ,1 单图,2 多图
        articleDto.setFlag((byte) 0);
//        补全频道的信息
        Integer channelId = wmNews.getChannelId();
        if (channelId != null) {
            articleDto.setChannelId(wmNews.getChannelId());
        }
        AdChannel channel = adChannelMapper.selectById(channelId);
        if (channel != null) {
//            设置频道的名称
            articleDto.setChannelName(channel.getName());
        }
        WmUser wmUser = wemediaFeign.findWmUserById(wmNews.getUserId());
        if (wmUser == null) {
            log.error("远程调用文章微服务 该文章关联的自媒体用户不存在 文章id={} 自媒体用户id={}", wmNews.getId(), wmNews.getUserId());
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST, "该文章关联自媒体用户不存在");
        }
        articleDto.setAuthorName(wmUser.getName());
        articleDto.setContent(wmNews.getContent());
        // 保存文章方法 返回文章id
        return articleFeign.saveArticle(articleDto);

    }

}
